<template>
  <canvas ref="canvasRef" class="scene-canvas" />
</template>

<script setup lang="ts">
import * as THREE from 'three'
import * as d3 from 'd3';
import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass";
import { UnrealBloomPass } from "three/examples/jsm/postprocessing/UnrealBloomPass";
import { OutlinePass } from "three/examples/jsm/postprocessing/OutlinePass";
import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer";
import { useWindowSize } from '@vueuse/core'
const { width, height } = useWindowSize()
import { threeTool, LightClass } from '@/utils/threeClass'
const canvasRef = ref()
const web3Dtool = new threeTool()
const lightTool = new LightClass()
import img3 from '@/assets/img/brick_roughness.jpg'
import hebei from './json/河北省.json'

let projectpos = d3.geoMercator().center([115.736577,39.625179]).scale(100).translate([0, 0])

const backgroundTexture = new THREE.TextureLoader().load( new URL('@/assets/img/41caa76c62a050ced9175310349dabef.png', import.meta.url).href );
const boundaryLineArr: THREE.Object3D<THREE.Object3DEventMap>[] = []
function initGeoJson() {
  const meshHeight = 0.2
  const map = new THREE.Group();
  hebei.features.forEach((item: any) => {
    //定义一个province的省份3d对象
    const province = new THREE.Object3D();
    //结构hebei。json中features。geometry.coordinates[0]的数组
    //对应的是每个点的坐标数组
    let {coordinates} = item.geometry;
    // initText(item.properties)
    coordinates.forEach((c: any) => {
      c.forEach((polygon: any) => {
        const shape = new THREE.Shape();
        const lineMaterial = new THREE.LineBasicMaterial({ color: 0xceebf7 });
        const lineGeometry = new THREE.BufferGeometry();
        const pointsArray = new Array();
        for (let i = 0; i < polygon.length; i++) {
          let [x, y] = projectpos(polygon[i]);
          if (i === 0) {
            // 创建起点,使用moveTo方法
            // 因为计算出来的y是反过来，所以要进行颠倒
            shape.moveTo(x, -y);
          }
          shape.lineTo(x, -y);
          pointsArray.push(new THREE.Vector3(x, -y, meshHeight));
        }
        lineGeometry.setFromPoints(pointsArray);
        const extrudsSettings = {
          depth: meshHeight,
          bevelEnabled: false//对挤出的形状进行斜角处理
        }
        const geometry = new THREE.ExtrudeGeometry(shape, extrudsSettings);
        geometry.computeBoundingBox();
        const material = new THREE.MeshBasicMaterial({ color: 0xcfc5de, transparent: true, opacity: 1, side: THREE.FrontSide });
        const material1 = new THREE.MeshLambertMaterial({ color: 0xcfc5de, transparent: true, opacity: 0.6, side: THREE.FrontSide });
        const mesh = new THREE.Mesh(geometry, [material, material1]);
        const line = new THREE.Line(lineGeometry, lineMaterial);
        province.properties = item.properties;
        //将城市信息放到模型中，后续做动画用
        if(item.properties.centroid){
          const [x,y] = projectpos(item.properties.centroid);
          province.properties._centroid = [x,y]
        }

        province.add(mesh);
        province.add(line);
        boundaryLineArr.push(line);
      })
    })

    let arr = [];
    let box = new THREE.Box3();
    for (let v of map.children) {
      for (let v2 of v.children) {
        // 判断是否为ExtrudeGeometry，只计算所有地图区域总和的包围盒大小
        if (v2.geometry instanceof THREE.ExtrudeGeometry) {
          arr.push(v2);
          let itemBox = new THREE.Box3().setFromObject(v2);
          box.union(itemBox);
        }
      }
    }
    var bboxMin = box.min;
    var bboxMax = box.max;
    // 计算UV的缩放比例
    var uvScale = new THREE.Vector2(
      1 / (bboxMax.x - bboxMin.x),
      1 / (bboxMax.y - bboxMin.y)
    );
    for (let v of arr) {
      let uvAttribute = v.geometry.getAttribute("uv");
      for (let i = 0; i < uvAttribute.count; i++) {
        let u = uvAttribute.getX(i);
        let v = uvAttribute.getY(i);
        // 将UV坐标进行归一化
        let normalizedU = (u - bboxMin.x) * uvScale.x;
        let normalizedV = (v - bboxMin.y) * uvScale.y;
        // 更新UV坐标
        uvAttribute.setXY(i, normalizedU, normalizedV);
      }
      // 更新几何体的UV属性
      v.geometry.setAttribute("uv", uvAttribute);
      v.material.map = backgroundTexture;
      v.material.needsUpdate = true;
    }
    map.add(province);
  })


  map.position.set(0, 0, 0);
  map.rotation.set(-Math.PI / 2, 0, 0);
  web3Dtool.scene.add(map);
  setLineOutline()
}
// 给地图边界线添加outline效果
  function setLineOutline() {
      //设置光晕
      const composer = new EffectComposer(web3Dtool.renderer); //效果组合器
      //创建通道
      let renderScene = new RenderPass(web3Dtool.scene, web3Dtool.cameras[web3Dtool.currentCamera]);
      composer.addPass(renderScene);

      let outlinePass = new OutlinePass(
        new THREE.Vector2(window.innerWidth, window.innerHeight),
        web3Dtool.scene,
        web3Dtool.cameras[web3Dtool.currentCamera],
        boundaryLineArr
      );
      console.log("🚀 ~ setLineOutline ~ boundaryLineArr:", boundaryLineArr)
      outlinePass.renderToScreen = true;
      outlinePass.edgeGlow = 2; // 光晕效果
      outlinePass.usePatternTexture = false;
      outlinePass.edgeThickness = 10; // 边框宽度
      outlinePass.edgeStrength = 1.5; // 光晕效果
      outlinePass.pulsePeriod = 0; // 光晕闪烁的速度
      outlinePass.visibleEdgeColor.set("#1acdec");
      outlinePass.hiddenEdgeColor.set("#1acdec");
      composer.addPass(outlinePass);
    }
onMounted(() => {
  web3Dtool.setCanvasMain({ bgColor: 0xf0f9ff, canvasEl: canvasRef.value })
  web3Dtool.initScene()
  web3Dtool.animateFun()

  initGeoJson()
})

// 5. 监听窗口大小变化
watch([width, height], e => {
  web3Dtool.watchUpdate(e[0], e[1])
})
</script>

<style scoped lang="scss">
.scene-canvas {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  outline: none;
}
</style>
